#include "units.h"
#include "init.h"
#include "rules.h"
#include "players.h"
#include "gui.h"
#include <queue>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>



void firstaidkit::effect( unit* u )
{
	u->set_health( u->get_health() + 50 );
	mapa::get_instance()->set_object( 0, this->get_x(), this->get_y() );
	delete this;
};



string unit::get_info()
{
	std::ostringstream st;
	st << "Price: " << price << "  Range: " << range << "  Health: " << health << "  Shield: " << shield << "  Weapon: " << weapon << "  Cost move: " << cost_move << "  Cost_fire: " << cost_fire;
	return st.str();
};



bool unit::move( unsigned int x, unsigned int y )
{
	std::queue< std::pair< unsigned int, unsigned int > >* path = new std::queue< std::pair< unsigned int, unsigned int > >;
	return move_handle( path, x, y );
};



//for gui's puropses
bool unit::move_handle( std::queue< std::pair< unsigned int, unsigned int > >* path, unsigned int x, unsigned int y )
{
	pre_move_info* pmi = new pre_move_info( this, x, y );
	//is movement possible?
	int d = test_move( path, this, x, y );
	if ( d != -1 )
	{	
		//pmi = pre move info
		pmi->path = path;
		pl->set_time( pl->get_time() - d );
		//bonus?
		bonus* b = dynamic_cast< bonus* >( mapa::get_instance()->get_object( x, y ) );
		if ( b!= 0 )
		{
			b->effect( this );
		}
		mapa::get_instance()->set_object( 0, pos_x, pos_y );
		//moves object
		set_pos( x, y );
		mapa::get_instance()->set_object( this, x, y );
		game_gui::get_instance()->show_move( this, x, y, pmi );
		return true;
	}
	else
	{
		return false;
	}
}



//owner hit
void unit::hit( unsigned int w )
{
	//shield effects ( min damage = 1 )
	int x = ( int )w - ( int )shield;
	if ( x > 0 )
		health -= x;
	else
		health -= 1;
	if ( health <= 0 )
	{
		//mortal hit
		mapa::get_instance()->set_object( 0, pos_x, pos_y );
		for ( vector< unit* >::iterator it = this->get_player()->units.begin(); it != this->get_player()->units.end(); ++it )
		{
			if ( *it == this )
			{
				this->get_player()->units.erase( it );
				break;
			}
		}
		delete this;
	}
};



bool unit::fire( unsigned int x, unsigned int y )
{
	return fire_handle( x, y );
};



//for gui's puropses
bool unit::fire_handle( unsigned int x, unsigned int y )
{
	//pfi = pre fire handle
	pre_fire_info* pfi = new pre_fire_info( this, x, y );
	//is attack possible?
	if ( test_fire( this, x, y ) )
	{
		unit* u;	
		if ( ( u = dynamic_cast< unit* >( mapa::get_instance()->get_object( x, y ) ) ) != 0 )
		{
			pl->set_time( pl->get_time() - ( int )cost_fire );
			//hits victim
			u->hit( weapon );
			game_gui::get_instance()->show_fire( this, x, y, pfi );
			game::get_instance()->test_game_end();
			return true;
		}
		else
		{
			return false;
		}

	}
	else
	{
		return false;
	}
};



int unit::get_id()
{
	for ( unsigned int i = 0; i < this->get_player()->units.size(); ++i )
	{
		if ( this->get_player()->units[ i ] == this )
			return i;
	}
	return -1;
};



prototypes* prototypes::get_instance()
{
	static prototypes inst( 0 );
	return &inst;
};



bool prototypes::load_types( const char* file )
{
	std::ifstream fin;
	fin.open( file, std::ifstream::in );
	if ( !fin.good() )
	{
		std::cout << "ERROR WHILE OPENING UNIT TYPES FILE" << std::endl;
		return false;
	}
	std::string unit_line;
	for ( ; ; )
	{
		std::getline( fin, unit_line );
		if ( fin.fail() )
		{
			break;
		}
		if ( !parse_unit_line ( unit_line ) )
		{
			std::cout << "ERROR WHILE READING UNIT TYPES FILE" << std::endl;
			return false;
		}
	}
	fin.close();
	std::cout << "UNIT TYPES LOADED SUCCESSFULLY" << std::endl;
	return true;
};



int prototypes::units_name_pos( std::string nm )
{
	int i;
	std::map< string, unit* >::iterator it2;
	for( it2 = units.begin(), i = 0; it2 != units.end(); ++it2, ++i )
	{
		if ( it2->first == nm )
			return i;
	}
	return -1;
};



int prototypes::units_iterator_pos( std::map< string, unit* >::iterator it )
{
	int i;
	std::map< string, unit* >::iterator it2;
	for( it2 = units.begin(), i = 0; it2 != units.end(); ++it2, ++i )
	{
		if ( it2->first == it->first )
			return i;
	}
	return -1;
};



std::map< string, unit* >::iterator prototypes::unit_pos_iterator( unsigned int p )
{
	int i;
	std::map< string, unit* >::iterator it;
	for( it = units.begin(), i = 0; it != units.end(); ++it, ++i )
	{
		if ( i == p )
			return it;
	}
	return units.end();
};



bool prototypes::parse_unit_line( std::string ul )
{
	if ( ul[0] == '#' )
		return true;
	std::istringstream sstr( ul );
	sstr.ignore( ul.size(), '"' );
	string name;
	std::getline( sstr, name, '"' );
	if ( name == "" )
		return true;
	unsigned int price;
	unsigned int range;
	unsigned int health;
	unsigned int shield;
	unsigned int weapon;
	unsigned int cost_move;
	unsigned int cost_fire;
	std::vector< std::pair< string, string > > icons( parameters::get_instance()->game_parameters[ "MAX_PL" ] );
	string sound_f;
	sstr >> price;
	sstr >> range;
	sstr >> health;
	sstr >> shield;
	sstr >> weapon;
	sstr >> cost_move;
	sstr >> cost_fire;
	if ( ( price < 1 ) || ( range < 1 ) || ( health < 1 ) || ( shield < 1 ) || ( weapon < 1 ) || ( cost_move < 1 ) || ( cost_fire < 1 ) )
		return false;
	if ( health > 20000 )
		health = 20000;
	//loading icons of units, for each possible player different color
	for ( unsigned int i = 0; i < parameters::get_instance()->game_parameters[ "MAX_PL" ]; ++i )
	{
		string icon_n;
		string icon_s;
		sstr >> icon_n;
		sstr >> icon_s;
		icons[ i ] = std::make_pair< string, string >( icon_n, icon_s );
	}
	sstr >> sound_f;

	if ( sstr.fail() )
		return false;

	prototypes::get_instance()->set_new_unit( name, price, range, health, shield, weapon, cost_move, cost_fire );
	game_gui::get_instance()->graphics->set_new_units_resources( name, icons, sound_f );
	std::cout << "LOADED UNIT TYPE: " << name << std::endl;

	return true;
};